#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>
#include <QFileDialog>
#include <string>
#include <iostream>
#include <fstream>
#include <vector>
#include <stdint.h>
#include <array>
#include <squish.h>
#include "binaryhelper.h"
#include "stringhelper.h"



MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}


MainWindow::~MainWindow()
{
    delete ui;
}


using namespace std;
typedef uint8_t byte;


template<size_t N>
void ArraySwap(array<int, N> &x, int size)
{
    for (int i = 0; i < size; i++)
    {
        x[i] = _byteswap_ulong(x[i]);
    }
}

class Texture
{
public:
    QString Name;
    int Width;
    int Height;
    QImage TextureImage;
    string Type;
    Texture(QString name, int width, int height, QImage teximg, string type)
    {
        Name = name;
        Width = width;
        Height = height;
        TextureImage = teximg;
        Type = type;
    }
};

vector<Texture> textures;
void MainWindow::on_btnOpen_clicked()
{
    QString filename = QFileDialog::getOpenFileName(this, tr("Open Pak File"), QDir::home().dirName(), tr(".pak Files (*.pak)"));
    if(filename == "")
        return;

    int headers[11];
        std::ifstream input(filename.toStdString(), std::ios::binary);

        input.seekg(0, std::ios::end);
        long size = input.tellg();
        input.seekg(0, std::ios::beg);

        input.read((char *)headers, 44);
        BinaryHelper::EndianSwap(headers,11);

        vector<array<int, 3>> data1(headers[4]);
        input.seekg(headers[5], ios_base::beg);

        for (int i = 0; i < headers[4]; i++)
        {
            input.read((char *)&data1[i], sizeof(int) * 3);
            ArraySwap(data1[i], 3);
        }

        int data2[200];
        input.seekg(headers[7], ios_base::beg);
        input.read((char *)data2, sizeof(int) * 3);
        BinaryHelper::EndianSwap(data2, 3);


        vector<array<int, 2>> data3(data2[2]);
        input.seekg(data2[1], ios_base::beg);

        for (int i = 0; i < data2[2]; i++)
        {
            input.read((char *)&data3[i], sizeof(int) * 2);
            ArraySwap(data3[i], 2);
        }

        for (int i = 0; i < headers[4]; i++)
        {
            int data4[6];
            input.seekg(data1[i][0], ios_base::beg);
            input.read((char *)data4, sizeof(int) * 2);
            for (int i = 2; i < 6; i++)
            {
                input.read((char *)&data4[i], sizeof(int)/2);
            }
            BinaryHelper::EndianSwap(data4, 6, 2);


            vector<array<int, 4>> data5(data4[5]);

            for (int i = 0; i < data4[5]; i++)
            {
                input.read((char *)&data5[i], sizeof(int) * 4);
                ArraySwap(data5[i], 4);
            }

            for (int c = 0; c < data4[5]; c++)
            {
                int data6[8];
                input.seekg(data1[i][0] + data5[c][2] , ios_base::beg);
                input.read((char *)data6, sizeof(int) * 8);
                BinaryHelper::EndianSwap(data6, 8);

                input.seekg(data1[i][0] + data6[3], ios_base::beg);
                string typeStr = BinaryHelper::ReadString(input);

                if (typeStr == ("VRAM_DESC"))
                {

                    int texInfo[22];
                    input.seekg(data1[i][0] + data5[c][2] + 0x20, ios_base::beg);

                    input.read((char *)texInfo, sizeof(int) * 4);
                    for (int i = 4; i < 22; i++)
                    {
                        input.read((char *)&texInfo[i], sizeof(int)/2);
                    }
                    BinaryHelper::EndianSwap(texInfo, 22, 4);

                    string texName = BinaryHelper::ReadString(input);
                    string textureName = "";
                    vector<string> v = StringHelper::split(texName, '/');


                    for (int i = 0; i < v.size(); i++)
                    {
                        string str = v[i];

                        int found = str.find("tga");
                        if (found > 0)
                        {
                            StringHelper::replaceString(str, ".tga", "");
                            textureName = str;
                            break;
                        }
                        found =  str.find("dds");
                        if (found > 0)
                        {
                            StringHelper::replaceString(str, ".dds", "");
                            textureName = str;
                            break;
                        }

                        textureName = "";

                    }

                    string type;
                    if (texInfo[6] == 0x600)
                        type = "DXT1";
                    else if (texInfo[6] == 0x800)
                        type = "DXT5";
                    else
                        type = "Unsupported";

                    ui->listWidget->addItem(QString::fromStdString(textureName));

                    input.seekg(((size - headers[8]) + texInfo[1]), ios_base::beg);

                    squish::u8 *buffer = new squish::u8[texInfo[2]];
                    squish::u8 *block = new squish::u8[texInfo[13] * texInfo[15] * 4 ];
                    input.read((char *)buffer, texInfo[2]);

                    if(type == "DXT1")
                        squish::DecompressImage(block, texInfo[13], texInfo[15], buffer, squish::kDxt1);
                    else if(type == "DXT5")
                        squish::DecompressImage(block, texInfo[13], texInfo[15], buffer, squish::kDxt5);

                    QImage img = QImage(block, texInfo[13], texInfo[15], texInfo[13] * 4, QImage::Format_ARGB32);
                    QImage imga = img.rgbSwapped();

                    Texture *tex = new Texture(QString::fromStdString(textureName), texInfo[13], texInfo[15], imga, type);
                    textures.push_back(*tex);

                }

            }


        }

}



void MainWindow::on_listWidget_itemSelectionChanged()
{
    int index =  ui->listWidget->currentRow();
    ui->label2->setPixmap(QPixmap::fromImage(textures[index].TextureImage));
    ui->label2->adjustSize();
}


